Skip to content

Fix CI test to actually use the Postgres database#9954

Open
browniebroke wants to merge 13 commits intoencode:mainfrom
browniebroke:fix/database-url-ci
Open

Fix CI test to actually use the Postgres database#9954
browniebroke wants to merge 13 commits intoencode:mainfrom
browniebroke:fix/database-url-ci

Conversation

@browniebroke
Copy link
Copy Markdown
Member

@browniebroke browniebroke commented Apr 7, 2026

Description

After merging #9949 I realised that the setup wasn't complete and Postgres tests are in fact skipped:

SKIPPED [7] tests/test_filters.py: Requires PostgreSQL database backend

This is because we run tests with tox and it needs to be instructed to pass environment variables down with the pass_env option.

Once this was set, the tests started failing with psycopg.errors.UndefinedTable: relation "auth_user" does not exist, which I fixed by passing --no-migrations to pytest.

Then a number of tests started failing due to hardcoded IDs and ordering assumptions which were no longer true.

@browniebroke browniebroke marked this pull request as ready for review April 28, 2026 21:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the CI/PostgreSQL test setup by ensuring tox passes DATABASE_URL through, adjusts pytest execution to avoid migration-related failures, and makes test behavior deterministic across database backends (notably PostgreSQL sequence behavior and queryset ordering).

Changes:

  • Configure tox to pass DATABASE_URL into test environments so PostgreSQL-required tests are exercised.
  • Run pytest with --no-migrations and adjust tests/fixtures to avoid Postgres-specific failures (missing tables, sequence/PK differences).
  • Stabilize tests by enforcing deterministic queryset ordering and backend-aware validator expectations.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tox.ini Passes DATABASE_URL into tox environments to enable Postgres-backed test runs.
pyproject.toml Adds --no-migrations to default pytest options to avoid migration/setup issues.
tests/conftest.py Adds an autouse fixture to reset Postgres sequences between tests for predictable PKs.
tests/test_validators.py Makes validator-count expectation backend-aware using connection.ops.integer_field_range.
tests/test_relations_slug.py Adds order_by('pk') to avoid nondeterministic ordering across DBs.
tests/test_relations_pk.py Adds order_by('pk') to avoid nondeterministic ordering across DBs.
tests/test_relations_hyperlink.py Adds order_by('pk') to avoid nondeterministic ordering across DBs.
tests/test_filters.py Increases a CharField(max_length=...) to avoid Postgres-enforced length failures.
rest_framework/test.py Attempts to prevent DB connection closing during RequestsClient WSGI calls by mutating Django signal handlers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tox.ini
dependency_groups =
test
deps =
pass_env =
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In [testenv:base], pass_env is currently set but left empty. In tox, setting pass_env = here overrides the inherited [testenv] value and will stop DATABASE_URL from being passed through for the base env, which undermines the goal of running Postgres-backed tests consistently. Either remove this pass_env override or include DATABASE_URL (and any other required vars) here as well.

Suggested change
pass_env =

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@auvipy this was intentional :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

owho!

Comment thread tests/conftest.py
Comment on lines +29 to +35
table_names = set(connection.introspection.table_names())
models = [m for m in apps.get_models() if m._meta.db_table in table_names]
sql_list = connection.ops.sequence_reset_sql(no_style(), models)
if sql_list:
with connection.cursor() as cursor:
for sql in sql_list:
cursor.execute(sql)
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This autouse fixture runs a full table introspection and sequence reset for every DB-using test on PostgreSQL (table_names() + apps.get_models() + executing reset SQL). That can add significant overhead to the test suite. Consider computing the relevant model list once per session (or caching sql_list) and only executing the reset SQL per test, or scoping the sequence reset to only the specific apps/tables that need stable PKs (or, ideally, updating the affected tests to avoid hard-coded PK assumptions).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each test use different models so that won't work in our test suite

Comment thread rest_framework/test.py Outdated
Comment on lines +94 to +104
# Disconnect close_old_connections to prevent closing the
# database connection during tests, matching the behavior
# of Django's ClientHandler.
environ = self.get_environ(request)
wsgi_response = self.app(environ, start_response)
request_started.disconnect(close_old_connections)
request_finished.disconnect(close_old_connections)
try:
wsgi_response = self.app(environ, start_response)
finally:
request_started.connect(close_old_connections)
request_finished.connect(close_old_connections)
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporarily disconnecting/reconnecting global request_started/request_finished signal receivers inside DjangoTestAdapter.send() is not thread-safe: concurrent requests in the same process could run while the handlers are disconnected, changing behavior outside this request. Also, if close_old_connections was connected with a dispatch_uid (or otherwise not matched by the disconnect() call), the connect() in finally can add a duplicate receiver. A safer approach is to avoid mutating global signals here (e.g., use Django’s ClientHandler for the WSGI call path, or otherwise ensure disconnect/connect is idempotent via the same dispatch_uid that Django uses).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants